package com.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.ar.ArArchiveEntry;
import org.apache.commons.compress.archivers.ar.ArArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorInputStream;
import org.apache.commons.compress.compressors.z.ZCompressorInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSONObject;

public class DebParser {
    private String[] ICON_TYPES = new String[] { "svg", "png", "jpg", "jpeg", "bmp" };
    private File debFile;

    public DebParser(File file) {
        debFile = file;
    }

    public JSONObject parse() throws ArchiveException, IOException {
        // 打开第一层的ar
        InputStream is = new FileInputStream(debFile);
        ArArchiveInputStream debInputStream = (ArArchiveInputStream) new ArchiveStreamFactory()
                .createArchiveInputStream("ar", is);
        ArArchiveEntry entry = null;
        String iconName = StringUtils.EMPTY;
        JSONObject control = null;

        while ((entry = (ArArchiveEntry) debInputStream.getNextEntry()) != null) {
            if (StringUtils.contains(entry.getName(), "control.tar")) {
                control = readFromTargetFile(entry.getName(), debInputStream, "control", ":");
            }
            if (StringUtils.contains(entry.getName(), "data.tar")) {
                // 获取图标位置
                JSONObject desktop = readFromTargetFile(entry.getName(), debInputStream, ".desktop", "=");
                if (desktop != null) {
                    iconName = desktop.getString("Icon");
                }
            }
        }
        debInputStream.close();

        if (StringUtils.isNotBlank(iconName)) {
            // 再次打开文件流获取图标文件,返回data类型
            if (StringUtils.isNotBlank(iconName)) {
                if (isFileUrl(iconName)) {
                    iconName = getUrlName(iconName);
                }

                JSONObject readIconData = readIconData(debFile, iconName);
                control.put("Icon", readIconData);
            }
        }

        return control;
    }

    private JSONObject readIconData(File debFile, String iconName) throws ArchiveException, IOException {
        JSONObject ret = new JSONObject();
        byte[] iconData = null;
        String format = StringUtils.EMPTY;
        
        // 打开第一层ar
        InputStream is = new FileInputStream(debFile);
        ArArchiveInputStream debInputStream = (ArArchiveInputStream) new ArchiveStreamFactory()
                .createArchiveInputStream("ar", is);
        ArArchiveEntry entry = null;

        while ((entry = (ArArchiveEntry) debInputStream.getNextEntry()) != null) {
            if (StringUtils.contains(entry.getName(), "data.tar")) {
                // 获取图标数据
                TarArchiveInputStream iconStream = getTarInputStream(entry.getName(), debInputStream);
                TarArchiveEntry entry2;
                while ((entry2 = iconStream.getNextTarEntry()) != null) {
                    if (entry2.isDirectory()) {
                        continue;
                    }

                    String urlName = getUrlName(entry2.getName());

                    // 判断文件名称是否相同
                    if (StringUtils.equals(urlName, iconName)) {
                        iconData = new byte[(int) entry2.getSize()];
                        IOUtils.read(iconStream, iconData);
                        format = StringUtils.substringAfterLast(urlName, ".");
                        break;
                    }

                    // 加上后缀匹配
                    for (int i = 0; i < ICON_TYPES.length; i++) {
                        String type = ICON_TYPES[i];
                        if (StringUtils.equals(urlName, iconName + "." + type)) {
                            iconData = new byte[(int) entry2.getSize()];
                            IOUtils.read(iconStream, iconData);
                            format = StringUtils.substringAfterLast(urlName, ".");
                            break;
                        }
                    }
                }

            }
        }
        debInputStream.close();
        
        ret.put("data",iconData);
        ret.put("format", format);

        return ret;
    }

    /**
     * *判断是否为文件完整路径
     * 
     * @param url
     * @return boolean
     */
    public static boolean isFileUrl(String url) {
        return StringUtils.contains(url, "/") || StringUtils.contains(url, "\\");
    }

    /**
     * *获取url上面的最后部分，也就是文件名+文件后缀
     * 
     * @param url
     * @return String
     */
    public static String getUrlName(String url) {
        String iconFileName = StringUtils.substringAfterLast(url, "/");
        if (StringUtils.isBlank(iconFileName)) {
            iconFileName = StringUtils.substringAfterLast(url, "\\");
        }

        return iconFileName;
    }

    /**
     * 读取targetFileName文件内容
     * 
     * @param deParseFileName
     * @param secondTar
     * @param targetFileName
     * @param sep 文件分隔符
     * @throws IOException void
     */
    public static JSONObject readFromTargetFile(String deParseFileName, InputStream secondTar, String targetFileName,
            String sep) throws IOException {

        TarArchiveInputStream controlTar = getTarInputStream(deParseFileName, secondTar);
        if (controlTar == null) {
            return null;
        }
        TarArchiveEntry entry;
        JSONObject read = null;
        while ((entry = controlTar.getNextTarEntry()) != null) {
            if (entry.isDirectory()) {
                continue;
            } else if (StringUtils.contains(entry.getName(), targetFileName)) {
                read = read(controlTar, sep);
            }
        }

        return read;
    }

    /**
     * *读取文件内容2字符串,封装到json对象返回
     * 
     * @param path 文件路径
     * @param sep 分隔符(key:value)
     * @return
     * @throws IOException JSONObject
     */
    private static JSONObject read(InputStream controlFile, String sep) throws IOException {

        BufferedReader reader = new BufferedReader(new InputStreamReader(controlFile));

        JSONObject info = new JSONObject();
        String input;
        String key = StringUtils.EMPTY;
        String value = StringUtils.EMPTY;
        while ((input = reader.readLine()) != null) {
            if (StringUtils.contains(input, sep)) {
                if (StringUtils.isNotBlank(key)) {
                    // 结束上一个匹配
                    info.put(key, value);
                }

                String[] split = StringUtils.split(input, sep, 2);
                if (split != null && split.length >= 2) {
                    key = split[0].trim();
                    value = split[1].trim();
                }
            } else {
                // 当前行是连着上一行value的
                value += input;
            }
        }

        // 将最后的key/value封装到JSON

        info.put(key, value);
        return info;
    }

    /**
     * *适配解压方式
     * 
     * @param tarPath
     * @return TarArchiveInputStream
     */
    public static TarArchiveInputStream getTarInputStream(String fileName, InputStream secondTar) {
        try {
            if (StringUtils.contains(fileName, "gz")) {
                return new TarArchiveInputStream(new GzipCompressorInputStream(secondTar));
            }

            if (StringUtils.contains(fileName, "bz2")) {
                return new TarArchiveInputStream(new BZip2CompressorInputStream(secondTar));
            }

            if (StringUtils.contains(fileName, "xz")) {
                return new TarArchiveInputStream(new XZCompressorInputStream(secondTar));
            }

            if (StringUtils.contains(fileName, "Z")) {
                return new TarArchiveInputStream(new ZCompressorInputStream(secondTar));
            }

            return new TarArchiveInputStream(secondTar);

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public static void main(String[] args) throws Exception {
        DebParser debParser = new DebParser(
                new File("C:\\Users\\Justsafe-Zhonglj\\Downloads\\linuxqq_2.0.0-b1-1024_amd64.deb"));
        JSONObject parse = debParser.parse();
        System.out.println(parse.toJSONString());
        JSONObject icon = parse.getJSONObject("Icon");
        byte[] bytes = icon.getBytes("data");
        String format = icon.getString("format");
        System.out.println(format);
        IOUtils.write(bytes, new FileOutputStream(new File("C:\\Users\\Justsafe-Zhonglj\\Downloads\\aa.png")));
    }
}
